﻿#include "ModelTestSene.h"

#include "Camera.h"
#include "Debuger.h"
#include "Mesh.h"
#include "Render.h"
#include "Light/Light.h"
#include "MaterialSrc/CubeMultipleLights.h"
#include "MaterialSrc/LightMaterial.h"


static std::vector<FVertexInfo> StaticVertices = {
	// positions          // normals           // texture coords
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f), glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(0.0f, 0.0f)},

	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(0.0f, 0.0f)},

	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f), -glm::vec3(1.0f,  0.0f,  0.0f), glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},

	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},

	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},

	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)}
};


void FModelTestScene::Init(FRender* InRender)
{
	FScence::Init(InRender);

	Camera = CreateDefaultCamera();

	this->InitLights();

	CubMesh = std::make_shared<FMesh>();
	const auto CubeMaterial = std::make_shared<FCubeMultipleLightMaterial>();
	auto CubVer = StaticVertices;
	CubMesh->Init(std::move(CubVer), CubeMaterial);

	const auto LightMaterial = std::make_shared<FLightMaterial>();
	LightMesh = std::make_shared<FMesh>();
	auto LightVer = StaticVertices;
	LightMesh->Init(std::move(LightVer), LightMaterial);

	MeshModel = std::make_shared<FMeshModel>();
	const bool LoadMeshOk = MeshModel->Load(FPath::BuildAssetsPath("nanosuit"), "nanosuit.obj");
	DebugerAssert(LoadMeshOk, "%hs", "加载模型出错");
}

void FModelTestScene::Destory()
{
	FScence::Destory();
}

void FModelTestScene::Draw(float DateTime)
{
	FScence::Draw(DateTime);

	auto Projection = glm::mat4(1.f);
	// Near 值不能太大 比如 10.f  会导致 0-10.f 之间的物体被剪裁，当相机靠近物体时，会有透视外挂的效果
	Projection = glm::perspective(glm::radians(Camera->GetFOV()), Render->GetAspect(), 0.1f, 100.0f);

	constexpr glm::vec3 CubePositions[] = {
		glm::vec3(0.0f,  0.0f,  0.0f),
		glm::vec3(2.0f,  5.0f, -15.0f),
		glm::vec3(-1.5f, -2.2f, -2.5f),
		glm::vec3(-3.8f, -2.0f, -12.3f),
		glm::vec3(2.4f, -0.4f, -3.5f),
		glm::vec3(-1.7f,  3.0f, -7.5f),
		glm::vec3(1.3f, -2.0f, -2.5f),
		glm::vec3(1.5f,  2.0f, -2.5f),
		glm::vec3(1.5f,  0.2f, -1.5f),
		glm::vec3(-1.3f,  1.0f, -1.5f)
	};

	const auto View = Camera->GetViewMat();

	FDrawArg DrawArg;
	DrawArg.DateTime = DateTime;
	DrawArg.LightArray = LightArray;
	DrawArg.ViewMat = View;
	DrawArg.ViewPos = Camera->GetPosition();
	DrawArg.ProjectionMat = Projection;

	Spotlight
		->SetDirection(Camera->GetFrontVector())
		->SetPosition(Camera->GetPosition());

	for (unsigned int I = 0; I < 10; I++)
	{
		auto Model = glm::mat4(1.0f);
		Model = glm::translate(Model, CubePositions[I]);
		const float Angle = 20.0f * I;
		Model = glm::rotate(Model, glm::radians(Angle), glm::vec3(1.0f, 0.3f, 0.5f));

		CubMesh->SetTransform(Model);
		CubMesh->Draw(DrawArg);
	}

	for (const auto& Light : PointLightArr)
	{
		glm::vec3 LightPos = Light->GetPosition();

		auto LightModel = glm::mat4(1.0);
		LightModel = glm::translate(LightModel, LightPos);
		LightModel = glm::scale(LightModel, glm::vec3(0.2f));

		LightMesh->SetTransform(LightModel);
		LightMesh->Draw(DrawArg);
	}

	glm::mat4 ModelMat(1.f);
	ModelMat = glm::translate(ModelMat, glm::vec3(0, -0.1, 0.1));
	ModelMat = glm::scale(ModelMat, glm::vec3(0.1f, 0.1f, 0.1f));
	MeshModel->SetTransform(ModelMat);
	MeshModel->Draw(DrawArg);
}

void FModelTestScene::InitLights()
{
	DirectionLight = std::make_shared<FDirectionLight>();
	LightArray.push_back(DirectionLight);

	DirectionLight
		->SetDirection(glm::vec3(-0.2f, -1.0f, -0.3f))
		->SetUniformStructName("light")
		->SetLightBaseValue(
			glm::vec3(0.05f, 0.05f, 0.05f),
			glm::vec3(0.4f, 0.4f, 0.4f),
			glm::vec3(0.5f, 0.5f, 0.5f));


	glm::vec3 PointLightPositions[] = {
		glm::vec3(0.7f,  0.2f,  2.0f),
		glm::vec3(2.3f, -3.3f, -4.0f),
		glm::vec3(-4.0f,  2.0f, -12.0f),
		glm::vec3(0.0f,  0.0f, -3.0f)
	};

	int32_t Index = 0;
	for (const auto& Pos : PointLightPositions)
	{
		PointLightArr[Index] = std::make_shared<FPointLight>();
		auto Light = PointLightArr[Index];

		char String[1024];
		sprintf(String, "pointLights[%d]", Index);

		Light
			->SetPosition(Pos)
			->SetPointAttenuationValue(1.0f, 0.09f, 0.032f)
			->SetUniformStructName(String)
			->SetLightBaseValue(glm::vec3(0.05f, 0.05f, 0.05f),
				glm::vec3(0.8f, 0.8f, 0.8f),
				glm::vec3(1.0f, 1.0f, 1.0f)
			);

		LightArray.push_back(Light);

		Index++;
	}

	Spotlight = std::make_shared<FSpotLight>();
	LightArray.push_back(Spotlight);

	Spotlight
		->SetCutOffAngle(12.5f, 15.0f)
		->SetDirection(Camera->GetFrontVector())
		->SetPosition(Camera->GetPosition())
		->SetPointAttenuationValue(1.0f, 0.09f, 0.032f)
		->SetUniformStructName("spotLight")
		->SetLightBaseValue(glm::vec3(0.0f, 0.0f, 0.0f),
			glm::vec3(1.0f, 1.0f, 1.0f),
			glm::vec3(1.0f, 1.0f, 1.0f)
		);
}
